/* * Copyright © 2023 https://www.cestc.cn/ All rights reserved. */
package com.ffz.calcitesql.sqlparser.nodeparser;

import com.ffz.calcitesql.sqlparser.enums.FunctionType;
import org.apache.calcite.sql.SqlBasicCall;
import org.apache.calcite.sql.SqlIdentifier;
import org.apache.calcite.sql.SqlJoin;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.SqlNodeList;
import org.apache.calcite.sql.SqlOrderBy;
import org.apache.calcite.sql.SqlSelect;
import org.apache.calcite.sql.util.SqlBasicVisitor;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.List;

/**
 * 解析Select.
 *
 * @author fengfazheng
 * @since 2024/1/16 15:37
 */
public class SelectNodeParser implements NodeParser {
    @Override
    public void parserSqlNode(SqlNode sqlNode) {
        SqlKind kind = sqlNode.getKind();
        switch (kind) {
            case SELECT:
                hanlerSelect(sqlNode);
                break;
            case UNION:
                ((SqlBasicCall) sqlNode).getOperandList().forEach(this::parserSqlNode);

                break;
            case ORDER_BY:
                handlerOrderBy(sqlNode);
                break;
        }
    }

    private void handlerOrderBy(SqlNode node) {
        SqlOrderBy sqlOrderBy = (SqlOrderBy) node;
        SqlNode query = sqlOrderBy.query;
        parserSqlNode(query);
        SqlNodeList orderList = sqlOrderBy.orderList;
        handlerField(orderList);
    }

    private void hanlerSelect(SqlNode select) {
        SqlSelect sqlSelect = (SqlSelect) select;
        SqlNodeList selectList = sqlSelect.getSelectList();
        for (SqlNode sqlNode : selectList) {
            assert sqlNode != null;
            handlerField(sqlNode);
        }
        assert sqlSelect.getFrom() != null;
        handlerFrom(sqlSelect.getFrom());

        if (sqlSelect.hasWhere()) {
            assert sqlSelect.getWhere() != null;
            handlerField(sqlSelect.getWhere());
        }

        if (sqlSelect.hasOrderBy()) {
            assert sqlSelect.getOrderList() != null;
            handlerField(sqlSelect.getOrderList());
        }

        SqlNodeList group = sqlSelect.getGroup();
        if (group != null) {
            for (SqlNode sqlNode : group) {
                handlerField(sqlNode);
            }
        }


        SqlNode fetch = sqlSelect.getFetch();
        if (fetch != null) {
            //TODO limit
        }

    }

    private void handlerFrom(SqlNode from) {
        SqlKind kind = from.getKind();

        switch (kind) {
            case IDENTIFIER:
                //最终的表名
                SqlIdentifier sqlIdentifier = (SqlIdentifier) from;
                //TODO 表名的替换，所以在此之前就需要获取到模型的信息
                System.out.println("==table name===" + sqlIdentifier);
                break;
            case AS:
                SqlBasicCall sqlBasicCall = (SqlBasicCall) from;
                SqlNode selectNode = sqlBasicCall.getOperandList().get(0);
                System.out.println("==table alias name===" + sqlBasicCall.getOperandList().get(1));
                handlerFrom(selectNode);
                break;
            case JOIN:
                handlerJoin(from);
                break;
            case SELECT:
                parserSqlNode(from);
                break;
        }
    }

    private void handlerJoin(SqlNode joinNode) {
        if (joinNode instanceof SqlJoin) {
            handlerJoin(((SqlJoin) joinNode).getLeft());
            handlerJoin(((SqlJoin) joinNode).getRight());
        } else if (joinNode instanceof SqlBasicCall) {
            handlerSqlBasicCall((SqlBasicCall) joinNode);
        } else if (joinNode instanceof SqlIdentifier) {
            System.out.println("===table name===" + joinNode);
        }
    }

    private void handlerSqlIdentifier(SqlIdentifier sqlIdentifier) {
        if (sqlIdentifier.names.size() > 1) {
            System.out.println("===per name===" + sqlIdentifier.names.get(0));
            System.out.println("===name===" + sqlIdentifier.names.get(1));
        } else {
            System.out.println("===name===" + sqlIdentifier.names.get(0));
        }
    }

    private void handlerSqlBasicCall(SqlBasicCall sqlBasicCall) {
        SqlKind kind = sqlBasicCall.getKind();
        switch (kind) {
            case AS:
                List<SqlNode> operandList = sqlBasicCall.getOperandList();
                System.out.println("===table name===" + operandList.get(0) + "===alias===" + operandList.get(1));
                break;
            case OTHER_FUNCTION:
                if(sqlBasicCall.getOperator().getName().equalsIgnoreCase(FunctionType.MAX.name())){
                    SqlNode sqlNode = sqlBasicCall.getOperandList().get(0);
                    if (sqlNode instanceof SqlIdentifier) {
                        handlerSqlIdentifier((SqlIdentifier) sqlNode);
                    }
                }
                break;
            default:
                break;
        }
    }

    private void handlerField(SqlNode field) {
        SqlKind kind = field.getKind();
        switch (kind) {
            case SELECT:
                hanlerSelect(field);
                break;
            case AS:
                List<SqlNode> operands_as = ((SqlBasicCall) field).getOperandList();
                SqlNode sqlNode = operands_as.get(0);
                if (sqlNode instanceof SqlBasicCall) {
                    // 处理函数情况
                    SqlBasicCall sqlBasicCall = (SqlBasicCall) sqlNode;
                    System.out.println("===field===" + sqlBasicCall + "===alias===" + operands_as.get(1));
                } else if (sqlNode instanceof SqlIdentifier) {
                    // 通用
                    SqlIdentifier fieldSqlIdentifier = (SqlIdentifier) sqlNode;
                    System.out.println("===field===" + fieldSqlIdentifier + "===alias===" + operands_as.get(1));
                }else if(sqlNode instanceof SqlSelect){
                    parserSqlNode(sqlNode);
                    System.out.println("===field===" + sqlNode + "===alias===" + operands_as.get(1));
                }
                break;
            case IDENTIFIER:
                //表示当前为子节点
                SqlIdentifier sqlIdentifier = (SqlIdentifier) field;
                System.out.println("===field===" + sqlIdentifier);
                break;
            case OTHER_FUNCTION:
                if (field instanceof SqlBasicCall) {
                    handlerSqlBasicCall((SqlBasicCall) field);
                }
                break;
            default:
                if (field instanceof SqlBasicCall) {
                    List<SqlNode> nodes = ((SqlBasicCall) field).getOperandList();
                    for (int i = 0; i < nodes.size(); i++) {
                        handlerField(nodes.get(i));
                    }
                }
                if (field instanceof SqlNodeList) {
                    List<@Nullable SqlNode> list = ((SqlNodeList) field).getList();
                    for (SqlNode node : list) {
                        assert node != null;
                        handlerField(node);
                    }
                }
                break;
        }


    }
}
